package gps.implementationAPI;

import gps.Colors;
import gps.Direction;
import gps.GPSRun;
import gps.api.GPSRule;
import gps.api.GPSState;
import gps.exception.NotAppliableException;
import gps.rules.Move;
import gps.states.SquareState;

import java.awt.Point;

public class GPSRuleImplementation implements GPSRule {
	
	private Integer cost;
	private Move m;
	
	public GPSRuleImplementation(Integer cost, Move m) {
		this.cost = cost;
		this.m = m;
	}
	
	public GPSRuleImplementation(Move m) {
		this (1, m);
	}
	
	public void setCost (Integer cost) {
		this.cost = cost;
	}

	public Integer getCost() {
		return this.cost;
	}

	public String getName() {
		return "Action: " + this.m.toString();
	}

	public GPSState evalRule(GPSState state) throws NotAppliableException {
		GPSState newState = new GPSStateImplementation();
		newState.copyState(state);
		Point blank = state.getBlank();
		switch (this.m) {
		case MOVE_DOWN:
			if (blank.x == GPSRun.N - 1) {
				throw new NotAppliableException();
			}
			newState.setElementState(blank.x, blank.y, changeStateMoveUp(state.getElementState(blank.x+1, blank.y)));
			newState.setAsBlank(blank.x+1, blank.y);
			break;
		case MOVE_UP:
			if (blank.x == 0) {
				throw new NotAppliableException();
			}
			newState.setElementState(blank.x, blank.y, changeStateMoveDown(state.getElementState(blank.x-1, blank.y)));
			newState.setAsBlank(blank.x-1, blank.y);
			break;
		case MOVE_LEFT:
			if (blank.y == 0) {
				throw new NotAppliableException();
			}
			newState.setElementState(blank.x, blank.y, changeStateMoveRight(state.getElementState(blank.x, blank.y-1)));
			newState.setAsBlank(blank.x, blank.y-1);
			break;
		case MOVE_RIGHT:
			if (blank.y == GPSRun.N - 1) {
				throw new NotAppliableException();
			}
			newState.setElementState(blank.x, blank.y, changeStateMoveLeft(state.getElementState(blank.x, blank.y+1)));
			newState.setAsBlank(blank.x, blank.y+1);
			break;
		}
		return newState;
	}
	
	private SquareState changeStateMoveDown (SquareState squareState) {
		SquareState square = new SquareState(squareState.getDirection(), squareState.getFirstColor(), squareState.getSndColor());
		if (squareState.getDirection() == Direction.VERTICAL) {
			return square;
		}
		square.setDirection(Direction.HORIZONTAL);
		if (squareState.getFirstColor() == squareState.getSndColor()) {
			square.setFirstColor(invertColor(square.getFirstColor()));
		} else {
			square.setSndColor(invertColor(square.getSndColor()));
			if (square.getFirstColor() == square.getSndColor()) {
				square.setDirection(Direction.NONE);
			}
		}
		return square;
	}
	
	private Colors invertColor (Colors color) {
		if (color == Colors.BLACK) {
			return Colors.WHITE;
		}
		return Colors.BLACK;
	}
	
	private SquareState changeStateMoveUp (SquareState squareState) {
		SquareState square = new SquareState(squareState.getDirection(), squareState.getFirstColor(), squareState.getSndColor());
		if (squareState.getDirection() == Direction.VERTICAL) {
			return squareState;
		}
		square.setDirection(Direction.HORIZONTAL);
		if (squareState.getFirstColor() == squareState.getSndColor()) {
			square.setSndColor(invertColor(square.getSndColor()));
		} else {
			square.setFirstColor(invertColor(square.getFirstColor()));
			if (square.getFirstColor() == square.getSndColor()) {
				square.setDirection(Direction.NONE);
			}
		}
		return square;
	}
	
	private SquareState changeStateMoveLeft (SquareState squareState) {
		SquareState square = new SquareState(squareState.getDirection(), squareState.getFirstColor(), squareState.getSndColor());
		if (squareState.getDirection() == Direction.HORIZONTAL) {
			return squareState;
		}
		square.setDirection(Direction.VERTICAL);
		if (squareState.getFirstColor() == squareState.getSndColor()) {
			square.setSndColor(invertColor(square.getSndColor()));
		} else {
			square.setFirstColor(invertColor(square.getFirstColor()));
			if (square.getFirstColor() == square.getSndColor()) {
				square.setDirection(Direction.NONE);
			}
		}
		return square;
	}
	
	private SquareState changeStateMoveRight (SquareState squareState) {
		SquareState square = new SquareState(squareState.getDirection(), squareState.getFirstColor(), squareState.getSndColor());
		if (squareState.getDirection() == Direction.HORIZONTAL) {
			return squareState;
		}
		square.setDirection(Direction.VERTICAL);
		if (squareState.getFirstColor() == squareState.getSndColor()) {
			square.setFirstColor(invertColor(square.getFirstColor()));
		} else {
			square.setSndColor(invertColor(square.getSndColor()));
			if (square.getFirstColor() == square.getSndColor()) {
				square.setDirection(Direction.NONE);
			}
		}
		return square;
	}

}
